﻿//===============================================================================
// Microsoft patterns & practices
// Windows Phone 7 Developer Guide
//===============================================================================
// Copyright © Microsoft Corporation.  All rights reserved.
// This code released under the terms of the 
// Microsoft patterns & practices license (http://wp7guide.codeplex.com/license)
//===============================================================================


namespace AzureToolkit
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.StorageClient;

    public class FilesBlobContainer : IAzureBlobContainer<byte[]>, IInitializer
    {
        private readonly CloudStorageAccount account;
        private readonly CloudBlobContainer container;
        private readonly string contentType;
        private readonly BlobContainerPermissions blobContainerPermissions;

        public FilesBlobContainer(string containerName, string contentType)
            : this(CloudConfiguration.GetStorageAccount(), containerName, contentType)
        {
        }

        public FilesBlobContainer(CloudStorageAccount account, string containerName, string contentType)
            : this(account, containerName, contentType, new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob })
        {
        }

        public FilesBlobContainer(CloudStorageAccount account, string containerName, string contentType, BlobContainerPermissions blobContainerPermissions)
        {
            this.account = account;
            this.contentType = contentType;
            this.blobContainerPermissions = blobContainerPermissions;

            var client = this.account.CreateCloudBlobClient();
            if (client == null)
            {
                throw new InvalidOperationException("Client is null.");
            }
            client.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(5));

            this.container = client.GetContainerReference(containerName.ToLowerInvariant());
        }

        public void Initialize()
        {
            if (this.container.CreateIfNotExist())
            {
                this.container.SetPermissions(this.blobContainerPermissions);
            }
        }

        public void Save(string objId, byte[] obj)
        {
            CloudBlob blob = this.container.GetBlobReference(objId);
            blob.Properties.ContentType = this.contentType;
            blob.UploadByteArray(obj);
        }

        public void SaveAsync(string objId, byte[] obj)
        {
            CloudBlob blob = this.container.GetBlobReference(objId);
            blob.Properties.ContentType = this.contentType;
            MemoryStream stream = new MemoryStream(obj);
            blob.BeginUploadFromStream(stream, (ar) =>
            {
                var resultBlob = ar.AsyncState as CloudBlob;
                resultBlob.EndUploadFromStream(ar);
            }, blob);
        }

        public byte[] Get(string objId)
        {
            CloudBlob blob = this.container.GetBlobReference(objId);
            try
            {
                return blob.DownloadByteArray();
            }
            catch (StorageClientException)
            {
                return null;
            }
        }

        public IEnumerable<byte[]> GetAll()
        {
            IEnumerable<IListBlobItem> blobItems = this.container.ListBlobs();

            return blobItems.Select(blobItem => ((IAzureBlobContainer<byte[]>)this).Get(blobItem.Uri.ToString())).ToList();
        }

        public Uri GetUri(string objId)
        {
            CloudBlob blob = this.container.GetBlobReference(objId);
            return blob.Uri;
        }

        public void Delete(string objId)
        {
            CloudBlob blob = this.container.GetBlobReference(objId);
            blob.DeleteIfExists();
        }

        public void DeleteContainer()
        {
            this.container.Delete();
        }
    }
}